package TrafficSim;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D;
import java.util.Vector;
import javax.swing.JLabel;
import javax.vecmath.Vector2d;

import TrafficSim.Intersection.TrafficDirection;

@SuppressWarnings("serial")
public class SimulationTrafficGraph extends JLabel {
	private Vector<Intersection> graph;
	private Graphics2D g2d;
	private ZoomAndPanListener z;
	private Image roadImage = null;


	public SimulationTrafficGraph(Vector<Intersection> intersections,
			ZoomAndPanListener z) {
		this.graph = intersections;
		this.z = z;

	}

	public void paint(Graphics g) {
		super.paintComponents(g);
		this.g2d = (Graphics2D) g;
		
		  if (z.somethingChanged()) {
		      // Create the road image if it doesn't exist
		      roadImage = createImage(super.getWidth(), super.getHeight());
		      // draw the roads to the image
		      g2d = (Graphics2D) roadImage.getGraphics();
		      // Use roadG like you would any other graphics
		      // object to draw the roads to an image
		      g2d.setTransform(z.getCoordTransform());
				double scale = z.getCoordTransform().getScaleX();		
				Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); 
				double actualX = z.getCoordTransform().getTranslateX()/-scale-50;
				double actualY = z.getCoordTransform().getTranslateY()/-scale-50;
				double actualWidth = dim.width/scale+50;
				double actualHeight = dim.height/scale+50;
		for (Intersection i : this.graph) {
			for (Intersection j : i.getNextIntersections()) {
				Street temp = i.getStreet(j);
				Street s = truncateStreet(temp, 20);
				Street nextS = truncateStreet(j.getNextStreetAntiClockWise(i
						.getStreet(j)), 20);
				Street prevS = truncateStreet(i.getPrevStreetAntiClockWise(i
						.getStreet(j)), 20);
				Point pos1 = s.getEnd();
				Point pos2 = s.getStart();
				if(actualX <= pos1.x && pos1.x <= actualX+actualWidth && actualY <=pos1.y && pos1.y <= actualHeight+actualY
						|| actualX <= pos2.x && pos2.x <= actualX+actualWidth && actualY <=pos2.y && pos2.y <= actualHeight+actualY){
				paintLane(g2d, s);
				
				Street streetA = truncateStreet(i.getStreet(j), 1);
				Street streetC = truncateStreet(i.getPrevStreetAntiClockWise(i
						.getStreet(j)), 1);
				paintCurve(g2d, prevS, s, streetC, i);
				paintCurve(g2d, s, nextS, streetA, j);
				if (temp.isOneWay()){
				paintMedian(g2d, i, j);}
				for (Intersection k: j.getNextIntersections()){
					s = truncateStreet(i.getStreet(j), 20);
					nextS = truncateStreet(j.getStreet(k), 20);
					streetA = truncateStreet(i.getStreet(j), 1);
					paintCurve(g2d, s, nextS, streetA, j);
				}
				}
			}
		}
		
//		System.out.println("Streets drawn");




		  } else {
		      // If the buffer image exists, you just need to draw it.
		      // Draw the road buffer image
		      g2d.drawImage(roadImage, 0, 0, null);
		      // Draw everything else ...
		      // g.draw...
		}

	}

	public Street truncateStreet(Street s, int cut) {
		Vector2d dir = new Vector2d(s.getEnd().x, s.getEnd().y);
		dir.sub(new Vector2d(s.getStart().x, s.getStart().y));
		dir.normalize();
		dir.scale(cut);
		Street temp = new Street(1);
		Vector2d start = new Vector2d(s.getStart().x, s.getStart().y);
		Vector2d end = new Vector2d(s.getEnd().x, s.getEnd().y);
		start.add(dir);
		end.sub(dir);
		temp.initStreet(new Point((int) start.x, (int) start.y), new Point(
				(int) end.x, (int) end.y));
		return temp;
	}
	
	private void paintMedian(Graphics2D g, Intersection i, Intersection j) {
		Stroke st = new BasicStroke(0.5f, BasicStroke.CAP_BUTT,
				BasicStroke.JOIN_ROUND, 1.0f, new float[] { 3.0f, 6.0f }, 0.0f);
		g.setStroke(st);
		g.setColor(Color.BLACK);
		Street interSectionStreet = new Street(1);
		interSectionStreet.initStreet(i.getPosition(), j.getPosition());
		Street tempCut = truncateStreet(interSectionStreet, 15);
		Point2D start = tempCut.getStart();
		Point2D end = tempCut.getEnd();
		g.draw(new Line2D.Float(start, end));
	}

	private void paintCurve(Graphics2D g, Street s, Street nextS,
			Street streetA, Intersection i) {
		g.setStroke(new BasicStroke(7.5f));
		g.setColor(Color.GRAY);
		if(i.getDirection(s, nextS) == TrafficDirection.STRAIGHT){
			Point2D start = getStartPoint(nextS, i);
			Point2D end = getStartPoint(s, i);
			Line2D path = new Line2D.Double(start, end);
			g.draw(path);
			return;
		}
		Point start = getStartPoint(nextS, i);
		Point tempStartA = getStartPoint(s, i);
		Point tempStreetAStart = getStartPoint(streetA, i);
		QuadCurve2D qu = new QuadCurve2D.Double(tempStartA.x, tempStartA.y, tempStreetAStart.x, tempStreetAStart.y,start.x, start.y);
		g2d.draw(qu);
	}
	
	private Point getStartPoint(Street s, Intersection i){
		Point tempStart = new Point(s.getStart().x, s.getStart().y);
		Point tempEnd = new Point(s.getEnd().x, s.getEnd().y);
		if (tempEnd.distance(i.getPosition()) < tempStart.distance(i
				.getPosition())) {
			tempStart = tempEnd;

		}
		return tempStart;
	}

	private void paintLane(Graphics2D g, Street s) {
		g.setStroke(new BasicStroke(7.5f));
		g.setColor(Color.GRAY);
		Point2D start = s.getStart();
		Point2D end = s.getEnd();
		Line2D path1 = new Line2D.Double(start, end);
		g.draw(path1);
	}

}
